#include<iostream>
#include<string>
#include<strings.h>
#include<cstring>
#include<functional>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>

#include"InetAddr.hpp"
#include"Log.hpp"
#include"ThreadPool.hpp"

enum
{
    SOCK_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,//监听
    USAGE_ERROR
};

const static int defaultsockfd = -1;//协议
const static int gbacklog = 16;

class TcpServer;

class ThreadData//线程数据
{
public:
    ThreadData(int fd,InetAddr addr,TcpServer *self)
    :sockcfd(fd)
    ,clientaddr(addr)
    ,self(self)
    {}
public:
int sockcfd;
InetAddr clientaddr;
TcpServer *self;
};

    using task_t = std::function<void()>;

class TcpServer
{
    public:
    TcpServer(int port)
        :_port(port)
        ,_listendsock(defaultsockfd)
        ,_isrunning(false)
    {}
    //初始化服务器
    void  InitServer()
    {
        //创建流式套接字
        _listendsock = ::socket(AF_INET,SOCK_STREAM,0);//流格式套接字
        if(_listendsock<0)
        {
            LOG(FATAL,"socket error");
            exit(SOCK_ERROR);
        }
        //创建成功
        LOG(DEBUG,"socket create sockfd is :%d\n",_listendsock);

        //绑定
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = bind(_listendsock,(struct sockaddr *)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind error");
            exit(BIND_ERROR);
        }
        LOG(DEBUG,"bing success sockfd is :%d\n",_listendsock);
        //tcp式面向连接，通信前必须先建立连接，服务器是被连接的
        //tcpserver启动 ，未来首先要一直等待客户连接到来
        n = ::listen(_listendsock,gbacklog);
        if(n<0)
        {
            LOG(FATAL,"listen error");
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG,"listen success,sockfd is : %d\n",_listendsock);
    }
    void Service(int sockfd,InetAddr client)//文件描述符，客户端
    {
        //打印客户ip 端口号
        LOG(DEBUG,"get a new link,info %s:%d,fd:%d\n",client.Ip().c_str(),client.Port(),sockfd);
        std::string clientaddr="["+client.Ip()+":"+std::to_string(client.Port())+"]#";
        while (true)
        {
           char inbuffer[1024];
           ssize_t n = read(sockfd,inbuffer,sizeof(inbuffer)-1);
           if(n>0)
           {
                inbuffer[n] = 0;
                std::cout<<clientaddr<<inbuffer<<std::endl;

                std::string echo_string = "[sever echo]#";
                echo_string+=inbuffer;

                write(sockfd,echo_string.c_str(),echo_string.size());//写
            }
            else if(n==0)
            {
                //客户端退出关闭连接
                LOG(INFO,"%s quit\n",clientaddr.c_str());
                break;
            }
            else
            {
                LOG(ERROR,"read error\n",clientaddr.c_str());
                break;
            }
            sleep(5);
            break;
        }
      std::cout<<"server开始退出"<<std::endl;
      shutdown(sockfd,SHUT_RD);//关闭
      std::cout<<"shut_rd"<<std::endl;
      sleep(10);
    }
    static void *HandlerSock(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData*>(args);
        td->self->Service(td->sockcfd,td->clientaddr);
        delete td;
        return nullptr;
    }
    void Loop()//环形
    {
        _isrunning = true;
        //不能直接接收数据，先获取连接
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(_listendsock,(struct sockaddr*)&peer,&len);
            if(sockfd<0)
            {
                LOG(WARNING,"accept errpr\n");
                continue;
            }
            //采用多线程
            pthread_t t;
            ThreadData *td = new ThreadData(sockfd,InetAddr(peer),this);
            pthread_create(&t,nullptr,HandlerSock,td);//将线程分离
            
        }
        _isrunning = false;
    }
    ~TcpServer()
    {
        if(_listendsock>defaultsockfd)
        {
            ::close(_listendsock);
        }
    }
    private:
    uint16_t _port;//端口号
    int _listendsock;//监听
    bool _isrunning;//运行状态；
};